package com.leo.utils;

import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import static android.os.Environment.MEDIA_MOUNTED;

/**
 * 文件操作相关类
 *
 * Created by leo on 15/4/10.
 *
 */
public class FileUtils {
    private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE";
    private final static int BUFFER_SIZE = 2048;
    public final static String FILE_EXTENSION_SEPARATOR = ".";
    public static final long KB = 1024;
    public static final long MB = 1024 * KB;
    private static final String TAG = FileUtils.class.getSimpleName();
    private static final String APK = ".apk";		// apk文件

    public static void zip(String[] files, String zipFile) throws IOException {
        BufferedInputStream origin = null;
        ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
        try {
            byte data[] = new byte[BUFFER_SIZE];

            for (int i = 0; i < files.length; i++) {
                FileInputStream fi = new FileInputStream(files[i]);
                origin = new BufferedInputStream(fi, BUFFER_SIZE);
                try {
                    ZipEntry entry = new ZipEntry(files[i].substring(files[i].lastIndexOf("/") + 1));
                    out.putNextEntry(entry);
                    int count;
                    while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
                        out.write(data, 0, count);
                    }
                } finally {
                    origin.close();
                }
            }
        } finally {
            out.close();
        }
    }

    public static void unzip(File zipFile, File f) throws IOException {
        unzip(new FileInputStream(zipFile), f);
    }

    public static void unzip(InputStream zipIs, File f) throws IOException {
        if (!f.exists() || !f.isDirectory()) {
            f.mkdirs();
        }
        ZipInputStream zin = new ZipInputStream(zipIs);
        try {
            ZipEntry ze = null;
            while ((ze = zin.getNextEntry()) != null) {
                File unzipFile = new File(f, ze.getName());
                if (ze.isDirectory()) {
                    if (!unzipFile.isDirectory()) {
                        unzipFile.mkdirs();
                    }
                } else {
                    FileOutputStream fout = new FileOutputStream(unzipFile, false);
                    try {
                        IOUtils.copy(zin, fout);
                    } finally {
                        zin.closeEntry();
                        IOUtils.closeQuietly(fout);
                    }
                }
            }
        } finally {
            zin.close();
        }
    }

    /**
     *  复制文件夹
     * @param srcDir
     * @param destDir
     * @throws IOException
     */
    public static void copyDirectiory(String srcDir, String destDir) throws IOException {
        if(srcDir == null || destDir == null) {
            return;
        }
        copyDirectiory(new File(srcDir), new File(destDir));
    }

    /**
     *  复制文件夹
     * @param sourceDir
     * @param targetDir
     * @throws IOException
     */
    public static void copyDirectiory(File sourceDir, File targetDir) throws IOException {
        if(sourceDir == null || targetDir == null || !sourceDir.exists()) {
            return;
        }
        if(!targetDir.exists()) {
            targetDir.mkdirs();
        }
        File[] file = sourceDir.listFiles();
        if(file == null) {
            return;
        }
        for (int i = 0; i < file.length; i++) {
            if (file[i].isFile()) {
                File sourceFile = file[i];
                File targetFile = new File(targetDir, file[i].getName());
                IOUtils.copy(sourceFile, targetFile);
            }
            if (file[i].isDirectory()) {
                copyDirectiory(new File(sourceDir, file[i].getName()), new File(targetDir, file[i].getName()));
            }
        }
    }

    /**
     *  移动文件夹
     * @param src
     * @param dst
     * @throws IOException
     */
    public static void move(File src, File dst) throws IOException {
        copyDirectiory(src, dst);
        src.delete();
    }

    /**
     *  计算文件夹大小
     * @param file
     * @return
     */
    public static long sizeOf(File file) {
        if (file == null || !file.exists()) {
            return 0L;
        }
        if (file.isDirectory()) {
            return sizeOfDirectory(file);
        } else {
            return file.length();
        }
    }

    /**
     *  计算文件夹大小
     * @param directory
     * @return
     */
    private static long sizeOfDirectory(File directory) {
        final File[] files = directory.listFiles();
        if (files == null) {
            return 0L;
        }
        long size = 0;

        for (final File file : files) {
            try {
                if (!isSymlink(file)) {
                    size += sizeOf(file);
                    if (size < 0) {
                        break;
                    }
                }
            } catch (IOException ignored) {
            }
        }

        return size;
    }

    public static boolean isSymlink(File file) throws IOException {
        if (file == null) {
            throw new NullPointerException("File must not be null");
        }
        File fileInCanonicalFile = null;
        if (file.getParent() == null) {
            fileInCanonicalFile = file;
        } else {
            File canonicalDir = file.getParentFile().getCanonicalFile();
            fileInCanonicalFile = new File(canonicalDir, file.getName());
        }

        return !fileInCanonicalFile.getCanonicalFile().equals(fileInCanonicalFile.getAbsoluteFile());
    }

    /**
     *  删除文件夹
     * @param file
     * @return
     */
    public static boolean delete(File file) {
        if (file == null) {
            return true;
        }
        if (!file.exists()) {
            return true;
        }
        if (file.isFile()) {
            return file.delete();
        }
        if (!file.isDirectory()) {
            return false;
        }
        for (File f : file.listFiles()) {
            if (f.isFile()) {
                f.delete();
            } else if (f.isDirectory()) {
                delete(f);
            }
        }
        return file.delete();
    }

    /**
     * 删除文件或文件夹
     * <ul>
     * <li>if path is null or empty, return true</li>
     * <li>if path not exist, return true</li>
     * <li>if path exist, delete recursion. return true</li>
     * <ul>
     *
     * @param path
     * @return
     */
    public static boolean delete(String path) {
        if (StringUtils.isEmpty(path)) {
            return true;
        }

        File file = new File(path);
        return delete(file);
    }

    /**
     * get file name from path, not include suffix
     * <p/>
     * <pre>
     *      getFileNameWithoutExtension(null)               =   null
     *      getFileNameWithoutExtension("")                 =   ""
     *      getFileNameWithoutExtension("   ")              =   "   "
     *      getFileNameWithoutExtension("abc")              =   "abc"
     *      getFileNameWithoutExtension("a.mp3")            =   "a"
     *      getFileNameWithoutExtension("a.b.rmvb")         =   "a.b"
     *      getFileNameWithoutExtension("c:\\")              =   ""
     *      getFileNameWithoutExtension("c:\\a")             =   "a"
     *      getFileNameWithoutExtension("c:\\a.b")           =   "a"
     *      getFileNameWithoutExtension("c:a.txt\\a")        =   "a"
     *      getFileNameWithoutExtension("/home/admin")      =   "admin"
     *      getFileNameWithoutExtension("/home/admin/a.txt/b.mp3")  =   "b"
     * </pre>
     *
     * @param filePath
     * @return file name from path, not include suffix
     * @see
     */
    public static String getFileNameWithoutExtension(String filePath) {
        if (StringUtils.isEmpty(filePath)) {
            return filePath;
        }

        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);
        int filePosi = filePath.lastIndexOf(File.separator);
        if (filePosi == -1) {
            return (extenPosi == -1 ? filePath : filePath.substring(0, extenPosi));
        }
        if (extenPosi == -1) {
            return filePath.substring(filePosi + 1);
        }
        return (filePosi < extenPosi ? filePath.substring(filePosi + 1, extenPosi) : filePath.substring(filePosi + 1));
    }

    /**
     * get folder name from path
     * <p/>
     * <pre>
     *      getFolderName(null)               =   null
     *      getFolderName("")                 =   ""
     *      getFolderName("   ")              =   ""
     *      getFolderName("a.mp3")            =   ""
     *      getFolderName("a.b.rmvb")         =   ""
     *      getFolderName("abc")              =   ""
     *      getFolderName("c:\\")              =   "c:"
     *      getFolderName("c:\\a")             =   "c:"
     *      getFolderName("c:\\a.b")           =   "c:"
     *      getFolderName("c:a.txt\\a")        =   "c:a.txt"
     *      getFolderName("c:a\\b\\c\\d.txt")    =   "c:a\\b\\c"
     *      getFolderName("/home/admin")      =   "/home"
     *      getFolderName("/home/admin/a.txt/b.mp3")  =   "/home/admin/a.txt"
     * </pre>
     *
     * @param filePath
     * @return
     */
    public static String getFolderName(String filePath) {

        if (StringUtils.isEmpty(filePath)) {
            return filePath;
        }

        int filePosi = filePath.lastIndexOf(File.separator);
        return (filePosi == -1) ? "" : filePath.substring(0, filePosi);
    }

    /**
     * get suffix of file from path
     * <p/>
     * <pre>
     *      getFileExtension(null)               =   ""
     *      getFileExtension("")                 =   ""
     *      getFileExtension("   ")              =   "   "
     *      getFileExtension("a.mp3")            =   "mp3"
     *      getFileExtension("a.b.rmvb")         =   "rmvb"
     *      getFileExtension("abc")              =   ""
     *      getFileExtension("c:\\")              =   ""
     *      getFileExtension("c:\\a")             =   ""
     *      getFileExtension("c:\\a.b")           =   "b"
     *      getFileExtension("c:a.txt\\a")        =   ""
     *      getFileExtension("/home/admin")      =   ""
     *      getFileExtension("/home/admin/a.txt/b")  =   ""
     *      getFileExtension("/home/admin/a.txt/b.mp3")  =   "mp3"
     * </pre>
     *
     * @param filePath
     * @return
     */
    public static String getFileExtension(String filePath) {
        if (StringUtils.isEmpty(filePath)) {
            return filePath;
        }

        int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR);
        int filePosi = filePath.lastIndexOf(File.separator);
        if (extenPosi == -1) {
            return "";
        }
        return (filePosi >= extenPosi) ? "" : filePath.substring(extenPosi + 1);
    }

    /**
     * Creates the directory named by the trailing filename of this file, including the complete directory path required
     * to create this directory. <br/>
     * <br/>
     * <ul>
     * <strong>Attentions:</strong>
     * <li>makeDirs("C:\\Users\\Trinea") can only create users folder</li>
     * <li>makeFolder("C:\\Users\\Trinea\\") can create Trinea folder</li>
     * </ul>
     *
     * @param filePath
     * @return true if the necessary directories have been created or the target directory already exists, false one of
     * the directories can not be created.
     * <ul>
     * <li>if {@link IOUtils#(String)} return null, return false</li>
     * <li>if target directory already exists, return true</li>
     * <li>return {@link File#mkdirs}</li>
     * </ul>
     */
    public static boolean makeDirs(String filePath) {
        String folderName = getFolderName(filePath);
        if (StringUtils.isEmpty(folderName)) {
            return false;
        }

        File folder = new File(folderName);
        return (folder.exists() && folder.isDirectory()) || folder.mkdirs();
    }

    /**
     * Indicates if this file represents a file on the underlying file system.
     *
     * @param filePath
     * @return
     */
    public static boolean isFileExist(String filePath) {
        if (StringUtils.isEmpty(filePath)) {
            return false;
        }

        File file = new File(filePath);
        return (file.exists() && file.isFile());
    }

    /**
     * Indicates if this file represents a directory on the underlying file system.
     *
     * @param directoryPath
     * @return
     */
    public static boolean isFolderExist(String directoryPath) {
        if (StringUtils.isEmpty(directoryPath)) {
            return false;
        }

        File dire = new File(directoryPath);
        return (dire.exists() && dire.isDirectory());
    }

    /**
     * function: 取得文件名(从url或本地文件路径)
     * @param path
     * @param ignorExtention 是否忽略后缀
     * @return
     */
    public static String getFileName(String path, boolean ignorExtention) {
        String result = path;
        if (CheckUtils.isNotEmpty(path)) {
            int startIndex = 0;
            if (result.contains("\\")) {
                startIndex = result.lastIndexOf("\\") + 1;
            } else if (result.contains("/")) {
                startIndex = result.lastIndexOf("/") + 1;
            }

            int endIndex = ignorExtention ? result.lastIndexOf(".") : result.length();
            result = result.substring(startIndex, endIndex);
        }
        return result;
    }

    /**function: 取得文件后缀名
     *
     * @param file
     * @return
     */
    public static String getFileExtension(File file) {
        String result = "";
        try {
            result = file.getName().substring(file.getName().lastIndexOf(".") + 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     *  获取目录可用存储空间大小
     *
     * @param path
     * @return
     */
    public static long getPathAvailableMemorySize(File path) {
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long availableBlocks = stat.getAvailableBlocks();
        return availableBlocks * blockSize;
    }

    /**
     * 获取目录可用存储空间大小
     * @param path
     * @return
     */
    public static long getPathAvailableMemorySize(String path) {
        return getPathAvailableMemorySize(new File(path));
    }

    /**
     * 保存文件到sd卡
     *
     * @param byteArray
     * @param dir
     * @param fileName
     * @return
     */
    public static File save(byte[] byteArray, String dir, String fileName) {
        if (byteArray == null)
            return null;

        // 创建文件
        if (!createFile(dir, fileName)) {
            return null;
        }

        File mf = new File(dir + fileName);
        OutputStream outputStream = null;

        try {
            outputStream = new FileOutputStream(mf);
            outputStream.write(byteArray);
            byteArray = null;
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "下载文件失败:" + e.getMessage());

            return null;
        }

        if (CheckUtils.isNotNull(outputStream)) {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            outputStream = null;
        }
        return mf;
    }


    /**
     * function: 删除文件
     *
     * @param filePath
     * @return
     *
     * @ author:linhuan 2014-12-25 下午3:29:13
     */
    public static boolean deleteFile(String filePath){
        boolean result = false;
        if (CheckUtils.isNotEmpty(filePath)){
            try {
                File file = new File(filePath);
                if (file.exists()){
                    result = file.delete();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     *  创建File
     * @param path
     * @param fileName
     * @return
     */
    public static boolean createFile(String path, String fileName) {

        File dir = new File(path);

        if (!dir.exists()) {
            boolean flag = dir.mkdirs();
            if (!flag) {
                System.gc();
                File dirSon = new File(path);
                dirSon.mkdir();
            }
        } else if (!dir.canWrite()) {
            dir.delete();
            File dirSon = new File(path);
            dirSon.mkdirs();
        }

        File file = new File(path + fileName);

        if (file.exists() || file.isFile()) {
            return false;
        } else {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     *   打开Asset的File
     * @param path
     * @param context
     * @return
     */
    public static InputStream openAssetFile(String path, Context context) {

        InputStream is = null;

        try {
            context.getAssets().open(path);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return is;
    }

    /**
     *
     * function: 从assets读取图片
     *
     * @param fileName
     * @param context
     * @return
     */
    public static Bitmap getImageFromAssetsFile(String fileName, Context context) {

        Bitmap image = null;
        InputStream is = null;

        try {
            is = context.getAssets().open(fileName);
            image = BitmapFactory.decodeStream(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (CheckUtils.isNotNull(is)) {
                try {
                    is.close();
                    is = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return image;
    }

    /**
     * 删除方法 这里只会删除某个文件夹下的文件，如果传入的directory是个文件，将不做处理
     *
     * @param directory
     */
    public static void deleteFilesByDirectory(File directory) {
        if (directory != null && directory.exists() && directory.isDirectory()) {
            for (File item : directory.listFiles()) {
                item.delete();
            }
        }
    }

    /**
     *  计算文件夹大小
     * @param file
     * @return
     */
    public static double getDirSize(File file) {
        // 判断文件是否存在
        if (file.exists()) {
            // 如果是目录则递归计算其内容的总大小
            if (file.isDirectory()) {
                File[] children = file.listFiles();
                double size = 0;
                for (File f : children)
                    size += getDirSize(f);
                return size;
            } else {
                // 如果是文件则直接返回其大小,以“K”为单位
                double size = (double) file.length() / 1024;
                return size;
            }
        } else {
            return 0.0;
        }
    }

    /**
     * 判断文件是否存在
     * @param filePath
     * @return
     */
    public static boolean fileIsExistence(String filePath) {
        if (CheckUtils.isNull(filePath)) {
            return false;
        }
        File file = new File(filePath);
        if (!file.exists()) {
            return false;
        }
        return true;
    }


    public static File getOwnCacheDirectory(String cacheDir, Context context) {
        File appCacheDir = null;
        if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
            appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
            if (!appCacheDir.exists()) {
                appCacheDir.mkdirs();
            }
        }
        if (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) {
            appCacheDir = StorageUtils.getCacheDirectory(context);
        }
        return appCacheDir;
    }

    private static boolean hasExternalStoragePermission(Context context) {
        int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);
        return perm == PackageManager.PERMISSION_GRANTED;
    }


}
